﻿/*
 * Project WarRoom
 * https://warroom.codeplex.com/
 *
 * Copyright 2012, Yi-Fan Liao
 *
 * This file is part of Project WarRoom.
 *
 * Project WarRoom is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 * 
 * Project WarRoom is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Project WarRoom.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Date: Fri Aug 24 21:41:08 2012 +0800
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;
using System.Xml.Linq;
using System.Xml;
using System.Threading;

namespace WarRoom.Web
{
    public partial class WarRoom : System.Web.UI.Page
    {
        private static XmlUtility xu = new XmlUtility();
        private static string xmlFilePath = xu.InitializeFilePath("~/App_Data/messages.xml");
        private static string xmlUserPath = xu.InitializeFilePath("~/App_Data/users.xml");

        protected void Page_Load(object sender, EventArgs e)
        {

        }

        [System.Web.Services.WebMethod]
        public static List<User> GetOnlineUsers()
        {
            MembershipUser currentUser = Membership.GetUser(HttpContext.Current.User.Identity.Name, true);
            //currentUser.LastActivityDate = DateTime.Now;

            List<User> userList = new List<User>();
            XDocument _UserXDocument = XDocument.Load(xmlUserPath);
            var result = from o in _UserXDocument.Descendants("XmlUser")
                         where (DateTime.Now.Subtract(Convert.ToDateTime(o.Element("LastActivityDate").Value)).TotalMinutes < 1)
                         orderby Convert.ToDateTime(o.Element("LastActivityDate").Value) ascending
                         select o;

            IList<XElement> xmlUserList = result.ToList();
            foreach (XElement xmlUser in xmlUserList)
            {
                User newUser = new User();
                newUser.UserName = xmlUser.Element("UserName").Value;
                newUser.Email = xmlUser.Element("Email").Value;
                newUser.LastActivityDate = Convert.ToDateTime(xmlUser.Element("LastActivityDate").Value);
                userList.Add(newUser);
            }

            return userList;
        }

        [System.Web.Services.WebMethod]
        public static List<Message> GetMessages()
        {
            List<Message> messages = new List<Message>();
            messages.AddRange(GetMessagesFromXml());
            return messages;
        }

        [System.Web.Services.WebMethod]
        public static List<Message> GetNewMessages(int messageId)
        {

            List<Message> messages = new List<Message>();
            messages.AddRange(GetMessagesFromXml(messageId));
            return messages;

        }

        [System.Web.Services.WebMethod]
        public static List<Message> GetOldMessages(int messageId)
        {

            List<Message> messages = new List<Message>();
            messages.AddRange(GetMessagesFromXml(messageId, true));
            return messages;

        }

        /// <summary>
        /// Race condition
        /// </summary>
        /// <param name="content"></param>
        [System.Web.Services.WebMethod]
        public static void SubmitMessage(string content)
        {
            int messageID;
            string userName;
            int category;
            string title;
            //string content;
            int likes;
            int dislikes;

            messageID = GetNextMessageId();
            userName = Membership.GetUser(HttpContext.Current.User.Identity.Name).ToString();
            category = 0;
            title = string.Empty;
            likes = 0;
            dislikes = 0;

            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFilePath);
            //XmlNode node;
            //node = doc.SelectSingleNode("//Messages/Message[position()!=../Message[position()] and (MessageID > ../Message/MessageID and not(MessageID < ../Message/MessageID))]");
            //messageID = Convert.ToInt32(node.Attributes["MessageID"].Value);
            //messageID = messageID + 1;

            XmlNode xmlMessageRoot = doc.CreateElement("Message");
            XmlNode xmlMessageID = doc.CreateElement("MessageID");
            XmlNode xmlSender = doc.CreateElement("Sender");
            XmlNode xmlCategory = doc.CreateElement("Category");
            XmlNode xmlTitle = doc.CreateElement("Title");
            XmlNode xmlContent = doc.CreateElement("Content");
            XmlNode xmlLikes = doc.CreateElement("Likes");
            XmlNode xmlDislikes = doc.CreateElement("Dislikes");
            XmlNode xmlSubmitDateTime = doc.CreateElement("SubmitDateTime");
            XmlNode xmlModifiedDateTime = doc.CreateElement("ModifiedDateTime");

            xmlMessageID.InnerText = messageID.ToString();
            xmlSender.InnerText = userName;
            xmlCategory.InnerText = category.ToString();
            xmlTitle.InnerText = title;
            //xmlContent.InnerText = content;
            xmlContent.AppendChild(doc.CreateTextNode(content));
            xmlLikes.InnerText = likes.ToString();
            xmlDislikes.InnerText = dislikes.ToString();
            xmlSubmitDateTime.InnerText = System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
            xmlModifiedDateTime.InnerText = System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");

            xmlMessageRoot.AppendChild(xmlMessageID);
            xmlMessageRoot.AppendChild(xmlSender);
            xmlMessageRoot.AppendChild(xmlCategory);
            xmlMessageRoot.AppendChild(xmlTitle);
            xmlMessageRoot.AppendChild(xmlContent);
            xmlMessageRoot.AppendChild(xmlLikes);
            xmlMessageRoot.AppendChild(xmlDislikes);
            xmlMessageRoot.AppendChild(xmlSubmitDateTime);
            xmlMessageRoot.AppendChild(xmlModifiedDateTime);

            doc.SelectSingleNode("Messages").AppendChild(xmlMessageRoot);
            doc.Save(xmlFilePath);
        }

        private static IEnumerable<Message> GetMessagesFromXml()
        {
            List<Message> messages = new List<Message>();
            XDocument xd = XDocument.Load(xmlFilePath);
            IEnumerable<XElement> result = (from xmlMessage in xd.Descendants("Message")
                                            orderby Convert.ToInt32(xmlMessage.Element("MessageID").Value) descending
                                            select xmlMessage).Take(300);

            MapXmlToMessage(messages, result);
            return messages.OrderBy(m => m.MessageID);
        }

        private static IEnumerable<Message> GetMessagesFromXml(int messageId, bool getPreviousMessages = false)
        {
            List<Message> messages = new List<Message>();
            IEnumerable<XElement> result;

            if (getPreviousMessages)
            {
                //do
                //{
                //    result = (from xmlMessage in xd.Descendants("Message")
                //              where Convert.ToInt32(xmlMessage.Element("MessageID").Value) < messageId
                //              orderby Convert.ToInt32(xmlMessage.Element("MessageID").Value) descending
                //              select xmlMessage).Take(10);
                //} while (result.Count<XElement>() == 0);

                //MapXmlToMessage(messages, result);
            }
            else
            {
                result = GetNewMessagesFromXml(messageId);

                MapXmlToMessage(messages, result);
            }

            return messages.OrderBy(m => m.MessageID);

        }

        private static IEnumerable<XElement> GetNewMessagesFromXml(int messageId)
        {
            XDocument xd = XDocument.Load(xmlFilePath);
            IEnumerable<XElement> result;
            result = (from xmlMessage in xd.Descendants("Message")
                      where Convert.ToInt32(xmlMessage.Element("MessageID").Value) > messageId
                      orderby Convert.ToInt32(xmlMessage.Element("MessageID").Value)
                      select xmlMessage);
            return result;
        }

        private static void MapXmlToMessage(List<Message> messages, IEnumerable<XElement> result)
        {
            IList<XElement> xmlMessages = result.ToList();
            foreach (XElement xmlMessage in xmlMessages)
            {
                Message newMessage = new Message();
                newMessage.MessageID = Convert.ToInt16(xmlMessage.Element("MessageID").Value);
                newMessage.Sender = xmlMessage.Element("Sender").Value;
                newMessage.Category = xmlMessage.Element("Category").Value;
                newMessage.Title = xmlMessage.Element("Title").Value;
                newMessage.Content = xmlMessage.Element("Content").Value;
                newMessage.Likes = Convert.ToInt16(xmlMessage.Element("Likes").Value);
                newMessage.Dislikes = Convert.ToInt16(xmlMessage.Element("Dislikes").Value);
                newMessage.SubmitDateTime = Convert.ToDateTime(xmlMessage.Element("SubmitDateTime").Value);
                newMessage.ModifiedDateTime = Convert.ToDateTime(xmlMessage.Element("ModifiedDateTime").Value);
                messages.Add(newMessage);
            }
        }

        private static int GetNextMessageId()
        {
            int nextId;
            XDocument xd = XDocument.Load(xmlFilePath);
            nextId = Int32.Parse((from xmlMessage in xd.Descendants("Message")
                                  orderby Convert.ToInt32(xmlMessage.Element("MessageID").Value) descending
                                  select xmlMessage).First().Element("MessageID").Value) + 1;

            return nextId;
        }
    }
}